package cn.wsalix.admin.service.impl;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Observable;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.anlaser.admin.BaseUser;
import cn.anlaser.exception.AccountException;
import cn.anlaser.exception.NutException;
import cn.anlaser.service.impl.CommonServiceImpl;
import cn.anlaser.status.FlagEnum;
import cn.anlaser.utils.SearchFilter;
import cn.anlaser.utils.SearchFilter.Operator;
import cn.wsalix.admin.entity.SysRole;
import cn.wsalix.admin.entity.SysUser;
import cn.wsalix.admin.form.UserForm;
import cn.wsalix.admin.repository.UserRepository;
import cn.wsalix.admin.repository.UserRoleRepository;
import cn.wsalix.admin.service.UserService;
import cn.wsalix.admin.status.UserEnum;
import cn.wsalix.config.AppConfig;
import cn.wsalix.constant.Global;
import cn.wsalix.exception.UserException;
import cn.wsalix.login.service.QQUserService;
import cn.wsalix.observable.service.LoginService;
import cn.wsalix.observable.service.RegisterService;
import cn.wsalix.observable.service.UserInfoUpService;
import cn.wsalix.shiro.credentials.RetryLimitHashedCredentialsMatcher;
import cn.wsalix.sys.service.VerifyCodeService;
import cn.wsalix.user.service.UserCenterService;
import cn.wsalix.user.service.UserInfoService;
import cn.wsalix.utils.UserUtils;
import cn.wsalix.utils.Utils;

@Service("userService")
public class UserServiceImpl extends
		CommonServiceImpl<UserForm, UserRepository, SysUser> implements
		UserService {
	@Autowired
	private UserRepository userRepository;
	@Autowired
	private UserRoleRepository userRoleRepository;
	@Autowired
	protected UserException userException;
	@Autowired
	protected UserUtils userUtils;

	@Autowired
	private Utils utils;
	@Autowired
	private AppConfig appConfig;
	@Autowired
	private VerifyCodeService verifyCodeService;
	@Autowired
	private QQUserService qqUserService;
	@Autowired
	private UserInfoService userInfoService;
	@Autowired
	private UserCenterService userCenterService;

	@Override
	public UserRepository getRepository() {
		return userRepository;
	}

	@Override
	public String module() {
		return "/admin/user";
	}

	@Cacheable(value = "accountCache", key = "#id")
	@Override
	public SysUser findById(Long id) {
		SysUser user = super.findById(id);
		if (user == null) {
			return null;
		}
		if (user.getUserInfo() == null) {
			user.setUserInfo(userInfoService.findByUser(user));
		}
		if (user.getUserCenter() == null) {
			user.setUserCenter(userCenterService.findById(user.getId()));
		}
		return user;
	}

	@Cacheable(value = "accountCache", key = "#username")
	@Override
	public SysUser findByUsername(String username) {
		logger.info("real querying account... {}", username);
		SysUser user = userRepository.findByUsernameOne(username);
		if (user == null) {
			return null;
		}
		if (user.getUserInfo() == null) {
			user.setUserInfo(userInfoService.findById(user.getId()));
		}
		if (user.getUserCenter() == null) {
			user.setUserCenter(userCenterService.findById(user.getId()));
		}
		return user;
	}

	@CacheEvict(value = "accountCache", key = "#entity.getId()")
	@Transactional
	@Override
	public SysUser edit(SysUser entity) {
		logger.info("entity:" + entity.toString());
		return super.edit(entity);
	}

	@CacheEvict(value = "accountCache", key = "#form.getId()")
	@Transactional
	@Override
	public SysUser edit(UserForm form) {
		logger.info("form:" + form.toString());
		if (form.getPassword() == null) {
			form.setPassword(null);
			return super.edit(form);
		}
		if (form.getPassword() != null && !form.getPassword().equals("****")) {
			SysUser obj = getRepository().findOne(form.getId());
			traversalAssign(form, obj);
			encryptPassword(obj);
			return super.edit(obj);
		}
		return null;
	}

	@Transactional
	@Override
	public SysUser add(UserForm form) {
		SysUser exUser = findByUsername(form.getUsername());
		if (exUser != null) {
			if (exUser.getFlag().ordinal() == FlagEnum.valid.ordinal()) {
				throw AccountException.CRT_ACCOUNT_EXIST;
			}
		} else {
			exUser = new SysUser();
		}
		traversalAssign(form, exUser);
		SysUser user = add(exUser);
		return user;
	}

	@Transactional
	@Override
	public SysUser add(SysUser entity) {
		SysUser exUser = findByUsername(entity.getUsername());
		if (exUser != null) {
			throw AccountException.CRT_ACCOUNT_EXIST;
		}
		if (entity.getPassword() != null) {
			encryptPassword(entity);
		}
		entity.setCreatedDate(new Date());// DateTime.now());
		entity.setFlag(FlagEnum.valid);
		SysUser user = super.add(entity);
		return user;
	}

	@Autowired
	private RetryLimitHashedCredentialsMatcher credentialsMatcher;
	private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();

	public void encryptPassword(SysUser user) {
		user.setSalt(randomNumberGenerator.nextBytes().toHex());
		String newPassword = new SimpleHash(
				credentialsMatcher.getHashAlgorithmName(), user.getPassword(),
				ByteSource.Util.bytes(user.getCredentialsSalt()),
				credentialsMatcher.getHashIterations()).toHex();

		user.setPassword(newPassword);
	}

	private boolean isExist(SysUser sysUser) {
		return userRepository.findByUsernameOne(sysUser.getUsername()) != null;
	}

	@Transactional
	@Override
	public String sendSms(UserForm form) {
		SysUser user = userRepository.findByUsernameOne(form.getUsername());
		switch (form.getCodeType()) {
		case register:
			if (user != null) {
				throw new NutException("user exist!");
			}
			verifyCodeService.register(form);
			break;
		case restPwd:
			if (user == null) {
				throw Global.getException("",
						userException.getResetUserUnExist());
			}
			verifyCodeService.restPwd(form);
			break;
		default:
			break;
		}

		// saveSms(form);// 应该先存储再发送
		/*
		 * if (entity.getFlag() == null) { throw
		 * Global.getException("sms.flag.unseting"); }
		 */
		// if (entity.getFlag().equals("2")) {// 1短信验证码2语音验证码
		/*
		 * HttpUtils.voiceSingleSend(Global.voiceConfig, entity.getUsername(),
		 * verifyCode);
		 */

		// } else {
		/*
		 * String mes = String.format(Global.smsContent, entity.getZType()
		 * .getTitle(), verifyCode);
		 * HttpUtils.smsSingleSend(Global.singleConfig, entity.getUsername(),
		 * mes);
		 */

		// }

		return "";

	}

	@Override
	public Class<SysUser> getEntityClazz() {
		return SysUser.class;
	}

	@Override
	public Map<String, SearchFilter> buildByForm(UserForm form) {
		Map<String, SearchFilter> filters = buildFilter();

		if (form.getUsername() != null && !form.getUsername().equals("")) {
			filters.put("username", new SearchFilter("username", Operator.EQ,
					form.getUsername()));
		}
		if (form.getNickname() != null && !form.getNickname().equals("")) {
			filters.put("nickname", new SearchFilter("nickname", Operator.LIKE,
					form.getNickname()));
		}
		if (form.getStatus() != null && form.getStatus() != null) {
			filters.put("status", new SearchFilter("status", Operator.LIKE,
					form.getStatus()));
		}
		/*
		 * if (form.getUserType() != null) { filters.put("userType", new
		 * SearchFilter("userType", Operator.EQ, form.getUserType().ordinal()));
		 * }
		 */
		if (form.getRoleId() != null) {
			filters.put("role.id", new SearchFilter("role.id", Operator.EQ,
					form.getRoleId()));
		}
		return filters;
	}

	//

	@Override
	public List<SysUser> findUnUsersByRoleId(Long roleId) {
		return userRepository.findUnUsersByRoleId(roleId);
	}

	@Override
	public List<SysUser> findUsersByRoleId(Long roleId) {
		return userRoleRepository.findUsersByRoleId(roleId);
	}
	@Transactional
	@Override
	public void update(Observable o, Object arg) {
		if (o instanceof LoginService) {

		}
		if (o instanceof RegisterService) {
			RegisterService userRegisterService = (RegisterService) o;
			if (arg instanceof UserForm) {
				UserForm userForm = (UserForm) arg;
				/*
				 * if (!userRegisterService.isEfficacyCode()) {// 效验码正确 throw
				 * Global.getException(userException .getVerifyCodeError()); }
				 * SysUser user = BeanMapper.map(userForm, SysUser.class);
				 * user.setUserType(UserTypeEnum.normal);
				 * user.setOnlineFlag(true); user.setStatus(UserEnum.lock);
				 */
				SysUser user = add(userForm);
				userForm.setUser(user);
				userRegisterService.setUser(user);
			}
		}

		if (o instanceof UserInfoUpService) {
			UserInfoUpService userInfoUpService = (UserInfoUpService) o;
			if (arg instanceof UserForm) {
				UserForm userForm = (UserForm) arg;
				SysUser user;
				switch (userForm.getChange()) {
				case add:
					break;
				case delete:
					user = findById(userForm.getId());
					user.setStatus(UserEnum.delete);
					user.setFlag(FlagEnum.delete);
					edit(user);
					break;
				case edit:
					user = findById(userForm.getId());
					userForm.setUser(user);
					edit(user);
					break;
				case focus:
					user = findById(userForm.getId());
					userForm.setUser(user);
					break;
				case friend:
					user = findById(userForm.getId());
					userForm.setUser(user);
					break;
				case role:
					user = findById(userForm.getId());
					userForm.setUser(user);
					SysRole oldRole = user.getRole();
					userForm.setOldRole(oldRole);
					SysRole role = userForm.getRole();
					user.setRole(role);
					user = edit(user);
					userInfoUpService.setUser(user);
					break;
				default:
					break;
				}
				if (userForm.getUser() != null) {
					userInfoUpService.setUser(userForm.getUser());
					return;
				}
				user = edit(userForm);
				userInfoUpService.setUser(user);
			}

		}
	}

	@Transactional
	@Override
	public SysUser editPwd(UserForm form) {
		SysUser exUser = userRepository.findOne(form.getId());
		if (exUser == null) {
			throw Global.getException("", userException.getUserUnExist());
		}
		exUser.setPassword(form.getPassword());
		encryptPassword(exUser);
		/*
		 * if (entity.getNickname() == null || entity.getNickname().equals(""))
		 * { entity.setNickname(entity.getUsername()); }
		 */
		super.edit(exUser);
		return exUser;
	}

	@Transactional
	@Override
	public SysUser editPwdByUserName(UserForm form) {
		SysUser exUser = userRepository.findOne(form.getId());
		if (exUser == null) {
			throw Global.getException("", userException.getUserUnExist());
		}
		exUser.setPassword(form.getPassword());
		encryptPassword(exUser);
		/*
		 * if (entity.getNickname() == null || entity.getNickname().equals(""))
		 * { entity.setNickname(entity.getUsername()); }
		 */
		super.edit(exUser);

		return exUser;
	}

	/*
	 * @Override public int findWxUserCount() { return
	 * userRepository.findWxUserCount(); }
	 */

	@CacheEvict(value = "myMenuCache", key = "#userId")
	@Override
	public void updateUserRole(Long userId) {
		// TODO 清空userId对应的缓存
		SysUser user = findById(userId);
		logger.info("UserService： clean user[" + user.getUsername() + "] roles");
	}

	@Transactional
	@Override
	public void onLogout(Long userId) {
		SysUser user = findById(userId);
		user.setOnlineFlag(false);
		super.edit(user);
	}

	@Transactional
	@Override
	public void setRole(Long userId, SysRole role) {
		SysUser user = findById(userId);
		user.setRole(role);
		super.edit(user);
	}

	@Override
	public SysUser getByCurr() {
		Subject subject = SecurityUtils.getSubject();
		BaseUser baseUser = (BaseUser) subject.getPrincipal();
		return findById(baseUser.getId());
	}

}
